﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyWeb.Repository.UnitOfWorks;
using SqlSugar;

namespace MyWeb.Extensions.ServiceExtensions.Filter
{
    /// <summary>
    /// 接口请求日志记录
    /// </summary>
    public class RequestLogFilterAttribute : ActionFilterAttribute
    {
        private readonly SqlSugarScope _dbBase;
        public RequestLogFilterAttribute(IUnitOfWorkManage unitOfWorkManage)
        {
            _dbBase = unitOfWorkManage.GetDbClient();
        }
        /// <summary>
        /// Action方法调用之前执行
        /// </summary>
        /// <param name="context "></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            try
            {
                HttpRequest request = context.HttpContext.Request;
                ////获取请求头中的Token和TimeSpan
                //var token = context.HttpContext.Request.Headers["Token"].ToString();
                //var timespan = context.HttpContext.Request.Headers["TimeSpan"].ToString();

                //string token = request.Headers["token"];

                var descriptor = context.ActionDescriptor as ControllerActionDescriptor;
                //记录进入请求的时间
                descriptor.Properties["enterTime"] = DateTime.Now.ToBinary();
                string Id = Guid.NewGuid().ToString().Substring(0, 12);
                //记录日志Id
                descriptor.Properties["Id"] = Id;

                //获取action名称
                string actionName = descriptor.ActionName;
                //获取Controller 名称
                string controllerName = descriptor.ControllerName;
                //获取action开始执行的时间
                DateTime enterTime = DateTime.Now;
                //获取访问的ip 及 端口
                string ip = context.HttpContext.Connection.RemoteIpAddress.ToString() + ':' + context.HttpContext.Connection.RemotePort.ToString();
                //获取用户主机名
                string userHostName = request.Host.Value;

                //获取完整请求地址
                string urlReferrer = new StringBuilder()
                .Append(request.Scheme)
                .Append("://")
                .Append(request.Host)
                .Append(request.PathBase)
                .Append(request.Path)
                .Append(request.QueryString)
                .ToString();
                //获取请求的浏览器名称
                string? browser = request.Headers["User-Agent"];
                //string userHostName = request.UserHostName;
                //string urlReferrer = request.UrlReferrer != null ? request.UrlReferrer.AbsoluteUri : "";
                //string browser = request.Browser.Browser + " - " + request.Browser.Version + " - " + request.Browser.Type;

                //获取request提交的参数
                string param = string.Empty;
                string globalParam = string.Empty;
                foreach (var arg in context.ActionArguments)
                {
                    string value = Newtonsoft.Json.JsonConvert.SerializeObject(arg.Value);
                    param += $"{arg.Key} : {value} \r\n";
                    globalParam += value;
                }
                //写入日志记录
                AddRequestLog(Id, Newtonsoft.Json.JsonConvert.SerializeObject(request.Headers), actionName, controllerName, urlReferrer, param, enterTime, ip, userHostName, browser);
            }
            catch (Exception ex) 
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// Action 方法调用后。Result 方法调用前执行
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context) { }

        /// <summary>
        /// Result 方法调用前执行
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuting(ResultExecutingContext context) { }

        /// <summary>
        /// Result 方法调用后执行
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            try
            {
                HttpResponse Response = context.HttpContext.Response;

                var descriptor = context.ActionDescriptor as ControllerActionDescriptor;
                object beginTime = null;
                double costTime = 0;
                DateTime nowDate = DateTime.Now;
                object id = "";
                if (descriptor.Properties.TryGetValue("enterTime", out beginTime))
                {
                    //获取进入请求的时间
                    DateTime time = DateTime.FromBinary(Convert.ToInt64(beginTime));
                    //获取执行action的耗时
                    costTime = (nowDate - time).TotalMilliseconds;
                }
                if (descriptor.Properties.TryGetValue("Id", out id)) { }
                //获取Response响应的结果
                string result = string.Empty;
                if (context.Result is ObjectResult)
                    result = Newtonsoft.Json.JsonConvert.SerializeObject(((ObjectResult)context.Result).Value);
                if (!string.IsNullOrEmpty(id.ToString()) && id.ToString() != "")
                {
                    EditRequestLog(id.ToString(), Newtonsoft.Json.JsonConvert.SerializeObject(Response.Headers), result, nowDate, costTime);
                }
            }
            catch { }
        }

        /// <summary>
        /// 异步，方法之前前后执行
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            Console.WriteLine("异步方法过滤之前");
            var resultContext = await next();
            Console.WriteLine("异步方法过滤之后");
        }
        /// <summary>
        /// 异步方法，结果返回前后执行
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            Console.WriteLine("异步结果过滤之前");
            var resultContext = await next();
            Console.WriteLine("异步结果过滤之后");
        }

        /// <summary>
        /// 添加Api请求记录
        /// </summary>
        /// <param name="ApiRequestLogId">请求日志Id</param>
        /// <param name="Headers">请求头部信息</param>
        /// <param name="ActionName">请求方法名</param>
        /// <param name="ControllerName">请求控制器名</param>
        /// <param name="UrlReferrer">请求完整地址</param>
        /// <param name="RequestParam">请求参数</param>
        /// <param name="TimeOn">请求开始时间</param>
        /// <param name="IpAddress">请求Ip地址</param>
        /// <param name="HostName">请求主机名</param>
        /// <param name="Browser">请求浏览器信息</param>
        public void AddRequestLog(string ApiRequestLogId, string Headers, string ActionName, string ControllerName, string UrlReferrer, string RequestParam, DateTime? TimeOn, string? IpAddress, string? HostName, string? Browser)
        {
            var param = new
            {
                ApiRequestLogId,
                Headers,
                ActionName,
                ControllerName,
                UrlReferrer,
                RequestParam,
                TimeOn,
                IpAddress,
                HostName,
                Browser
            };

            // sapParameter = sapParameter.Replace("'","\"");
            string sqlstr = $@"INSERT INTO dbo.ApiRequestLog
                    (
                        ApiRequestLogId,
                        Headers,
                        ActionName,
                        ControllerName,
                        UrlReferrer,
                        RequestParam,
                        TimeOn,
                        IpAddress,
                        HostName,
                        Browser
                    )
                    VALUES
                    (   @ApiRequestLogId,
                        @Headers,
                        @ActionName,
                        @ControllerName,
                        @UrlReferrer,
                        @RequestParam,
                        @TimeOn,
                        @IpAddress,
                        @HostName,
                        @Browser
                        )";

            // _logger.LogError(sqlstr);
            try
            {
                var count = _dbBase.Ado.ExecuteCommand(sqlstr, param);
            }
            catch{ }
        }

        /// <summary>
        /// 更新Api请求记录
        /// </summary>
        /// <param name="ApiRequestLogId">接口日志Id</param>
        /// <param name="Response">响应头</param>
        /// <param name="ResultParam">返回参数</param>
        /// <param name="TimeOff">请求结束时间</param>
        /// <param name="CostTime">请求耗时（ms）</param>
        public void EditRequestLog(string ApiRequestLogId, string Response, string ResultParam, DateTime TimeOff, double CostTime)
        {
            var param = new
            {
                ApiRequestLogId,
                Response,
                ResultParam,
                TimeOff,
                CostTime
            };
            string sqlstr = $@"UPDATE dbo.ApiRequestLog SET Response = @Response,ResultParam = @ResultParam,TimeOff = @TimeOff,CostTime = @CostTime WHERE ApiRequestLogId = @ApiRequestLogId";
            try
            {
                var count = _dbBase.Ado.ExecuteCommand(sqlstr, param);
            }
            catch { }
        }
    }
    /// <summary>
    /// 不需要登陆的地方加个这个空的拦载器
    /// </summary>
    public class NoSignAttribute : ActionFilterAttribute { }
}
